package com.stone.serverless.rpc.service;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.loadbalancer.*;
import com.stone.serverless.rpc.RpcOkhttpComponentProvider;
import com.stone.serverless.rpc.loadbalancer.ServerInfo;
import com.stone.serverless.rpc.loadbalancer.StoneLoadBalancerRule;
import com.stone.serverless.rpc.loadbalancer.StoneServerList;
import com.stone.serverless.sdk.utils.InvokeUtil;
import com.stone.serverless.sdk.utils.JsonUtil;
import lombok.SneakyThrows;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: TODO
 * @Author: MECHREVO
 * @Date: 2022/1/25 12:53
 * @Version: 1.0.0
 */
@Component
public class RemoteCallServiceImpl implements RemoteCallService {

    private OkHttpClient builder = new OkHttpClient.Builder().build();

    private Map<String, ILoadBalancer> loadBalancerMap = new HashMap<>();

    @PostConstruct
    public void init() {
        RpcOkhttpComponentProvider.INSTANCE.add(this);
    }

    @Override
    @SneakyThrows
    public Object invoke(String serviceName, String version, Object[] args, Method method) {
        //找到注册中心
        //methodClass
        Class<?> declaringClass = method.getDeclaringClass();

        String classUrl = declaringClass.getName();

        String methodUrl = method.getName();

        if (!loadBalancerMap.containsKey(serviceName)) {
            initLoadBalancer(serviceName);
        }

        ILoadBalancer loadBalancer = loadBalancerMap.get(serviceName);

        Server server = loadBalancer.chooseServer(new ServerInfo(serviceName, version));
        if(ObjectUtil.isNull(server)){
            System.out.println("没有存活的实例");
            return null;
        }
        Request request = new Request.Builder()
                .url("http://" + server.getHostPort() + "/" + serviceName + "/" + version + "/" + classUrl + "/" + methodUrl).build();

        if (args.length > 0) {
            FormBody.Builder builder = new FormBody.Builder();
            Parameter[] parameters = method.getParameters();
            for (int i = 0; i < args.length; i++) {
                Parameter parameter = parameters[i];
                builder.add(parameter.getName(), JsonUtil.toStr(args[i]));
            }
            request = request.newBuilder().post(builder.build()).build();
        }
        Response execute = builder.newCall(request).execute();

        String string = execute.body().string();
        if (execute.code() != 200) {
            System.out.println(string);
        }
        Class<?> returnType = method.getReturnType();
        if (returnType != void.class && JSONUtil.isJson(string)) {
            Type genericReturnType = method.getGenericReturnType();
            InvokeUtil.TypeInfo returnTypeInfo = InvokeUtil.getTypeInfo(returnType, genericReturnType, CharSequenceUtil.concat(true, returnType.getName(), StrPool.UNDERLINE, genericReturnType.getTypeName()));
            Object copy = InvokeUtil.transfer(string, returnTypeInfo);
            return copy;
        } else {
            return null;
        }
    }

    public void initLoadBalancer(String serviceName) {
        StoneServerList stoneServerList = new StoneServerList();
        DefaultClientConfigImpl defaultClientConfig = new DefaultClientConfigImpl();
        defaultClientConfig.setClientName(serviceName);
        stoneServerList.initWithNiwsConfig(defaultClientConfig);
        ZoneAwareLoadBalancer<Server> serverZoneAwareLoadBalancer = LoadBalancerBuilder.newBuilder()
                .withClientConfig(defaultClientConfig)
                .withRule(new StoneLoadBalancerRule())
                .withDynamicServerList((ServerList) stoneServerList)
                .buildDynamicServerListLoadBalancer();


        //
        //List<Server> collect = allService.stream().map(v -> {
        //    Server server = new Server( v.getIp(), v.getPort());
        //    server.setId(v.getInstanceId());
        //    return server;
        //}).collect(Collectors.toList());

        //  serverZoneAwareLoadBalancer.addServers(collect);
        loadBalancerMap.put(serviceName, serverZoneAwareLoadBalancer);
    }


}
